// LineDisplay.cpp : Implementation of CLineDisplay

#include "stdafx.h"
#include "LineDisplay.h"
#include "Opos.h"
#include "Opos.hi"
#include "OposDisp.h"
#include <atlstr.h>

#include "VC220.h"

#define SET_RC(X)	*pRC = X; m_lResultCode = X;

#define METHOD_INVOKE_PRE_CHECK  if (!m_bOpened)\
	{\
		SET_RC(OPOS_E_CLOSED);\
		return S_FALSE;\
	}\
	if (!m_bEnabled)\
	{\
		SET_RC(OPOS_E_DISABLED);\
		return S_FALSE;\
	}\
	if(!m_bClaimed)\
	{\
		SET_RC(OPOS_E_NOTCLAIMED);\
		return S_FALSE;\
	}\
	if (NULL == m_pLD)\
	{\
		SET_RC(OPOS_E_NOSERVICE);\
		return S_FALSE;\
	}

// Service object description and version
TCHAR g_ServiceDescription[] = _T("Purong OPOS LineDisplay Service Object 1.12.0");
long g_ServiceVersion =   1 * 1000000 +   12 * 1000 +   1;

using namespace LineDisplayImp;

// CLineDisplay

CLineDisplay::CLineDisplay()
{
//	m_pLD = NULL;

	m_bOpened = FALSE;
	m_bClaimed = FALSE;
	m_bEnabled = FALSE;
	m_error = OPOS_E_CLOSED;

	m_pLD = NULL;

	m_bOpened = FALSE;
	m_lOpenResult = OPOS_OR_FAILEDOPEN;
	m_lResultCode = OPOS_SUCCESS;
	m_lState = OPOS_S_CLOSED;
}


STDMETHODIMP CLineDisplay::Claim(LONG Timeout, LONG *pRC)
{
	return ClaimDevice(Timeout, pRC);
}

STDMETHODIMP CLineDisplay::CloseService(LONG *pRC)
{
	return Close(pRC);
}

STDMETHODIMP CLineDisplay::SetDescriptor(LONG Descriptor, LONG Attribute, LONG *pRC)
{
	return S_OK;
}

STDMETHODIMP CLineDisplay::ScrollText(LONG Direction, LONG Units, LONG *pRC)
{
	return S_OK;
}

STDMETHODIMP CLineDisplay::RefreshWindow(LONG Window, LONG *pRC)
{
	return S_OK;
}

STDMETHODIMP CLineDisplay::DisplayTextAt(LONG Row, LONG Column, BSTR Data, LONG Attribute, LONG *pRC)
{
	METHOD_INVOKE_PRE_CHECK;

	m_lState = OPOS_S_BUSY;
	switch(Attribute)
	{
	case DISP_DT_NORMAL:
	case DISP_DT_BLINK:
	case  DISP_DT_REVERSE:
	case  DISP_DT_BLINK_REVERSE:
		m_pLD->DisplayTextAt(Row, Column, wstring(Data), Attribute);
		break;
	default:
		break;
	}

	m_lState = OPOS_S_IDLE;

	return S_OK;
}

STDMETHODIMP CLineDisplay::DisplayText(BSTR Data, LONG Attribute, LONG *pRC)
{
	METHOD_INVOKE_PRE_CHECK;

	m_lState = OPOS_S_BUSY;
	switch(Attribute)
	{
	case DISP_DT_NORMAL:
	case DISP_DT_BLINK:
	case  DISP_DT_REVERSE:
	case  DISP_DT_BLINK_REVERSE:
		m_pLD->DisplayText(wstring(Data), 0);
		break;
	default:
		break;
	}

	m_lState = OPOS_S_IDLE;

	return S_OK;
}

STDMETHODIMP CLineDisplay::DestroyWindow(LONG *pRC)
{
	return S_OK;
}

STDMETHODIMP CLineDisplay::ClearText(LONG *pRC)
{
	METHOD_INVOKE_PRE_CHECK;

	m_pLD->ClearText();

	return S_OK;
}

STDMETHODIMP CLineDisplay::ClearDescriptors(LONG *pRC)
{
	return S_OK;
}

STDMETHODIMP CLineDisplay::GetOpenResult(LONG *pRC)
{
	return S_OK;
}

STDMETHODIMP CLineDisplay::ReleaseDevice(LONG* pRC)
{
	if (!m_bOpened)
	{
		SET_RC(OPOS_E_CLOSED);
		return S_FALSE;
	}

	if (m_bEnabled || !m_bClaimed)
	{
		SET_RC(OPOS_E_ILLEGAL);
		return S_FALSE;
	}

	if (NULL == m_pLD)
	{
		SET_RC(OPOS_E_NOSERVICE);
		return S_FALSE;
	}

	if (0 != m_pLD->Close())
	{
		SET_RC(OPOS_E_FAILURE);
		return S_FALSE;
	}
	
	m_bClaimed = FALSE;
	
	SET_RC(OPOS_SUCCESS);
	return S_OK;
}

STDMETHODIMP CLineDisplay::DirectIO(LONG Command, LONG *pData, BSTR *pString, LONG *pRC)
{
	return S_OK;
}

STDMETHODIMP CLineDisplay::Close(LONG *pRC)
{
	if(m_bEnabled)
	{
		SET_RC(OPOS_E_ILLEGAL);
		m_lState = OPOS_S_ERROR;
	}
	if (!m_bOpened)
	{
		SET_RC(OPOS_E_CLOSED);
		m_lState = OPOS_S_ERROR;
	}

	if (m_bClaimed)
	{
		SET_RC(OPOS_E_CLAIMED);
		m_lState = OPOS_S_ERROR;
	}

	m_bOpened = FALSE;
	m_lState = OPOS_S_CLOSED;

	return S_OK;
}


STDMETHODIMP CLineDisplay::ClaimDevice(LONG timeout, LONG* pRC)
{
	// TODO: Add your implementation code here

	if (!m_bOpened)
	{
		SET_RC(OPOS_E_CLOSED);
		m_lState = OPOS_S_ERROR;
		return S_FALSE;
	}

	if (m_bClaimed)
	{
		SET_RC(OPOS_E_CLAIMED);
		m_lState = OPOS_S_ERROR;
		return S_FALSE;
	}

	if (NULL == m_pLD)
	{
		SET_RC(OPOS_E_NOSERVICE);
		m_lState = OPOS_S_ERROR;
		return S_FALSE;
	}

	DWORD dwTick = GetTickCount();
	DWORD dwTimeout = 0;
	do 
	{
		if (0 == m_pLD->Open())
		{
			SET_RC(OPOS_SUCCESS);
			m_bClaimed = TRUE;
			return S_OK;
		}

		dwTimeout = GetTickCount() - dwTick;

	} while (dwTimeout < (DWORD)timeout);

	SET_RC(OPOS_E_TIMEOUT);
	m_lState = OPOS_S_ERROR;
	
	return S_FALSE;
}

STDMETHODIMP CLineDisplay::CheckHealth(LONG Level, LONG* pRC)
{
	// Step 1. Add Log Information first.

	// Step 2. 



	return S_OK;
}

STDMETHODIMP CLineDisplay::OpenService(BSTR DeviceClass, BSTR DeviceName, IDispatch *pDispatch, LONG* pRC)
{
	// Open register table
	CString strBazeKey(OPOS_ROOTKEY);
	strBazeKey.Append(_T("\\"));
	strBazeKey.Append(DeviceClass);

//	TCHAR szBaseKey[256];
	HKEY hBaseKey;
	if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE,strBazeKey,0,KEY_READ,&hBaseKey))
	{
		m_error = OPOS_OR_REGBADNAME;
		*pRC = m_error;
		
		return S_FALSE;
	}
	
	HKEY hServiceKey;
	long lRet = RegOpenKeyEx(hBaseKey, (CString)DeviceName,0,KEY_READ,&hServiceKey);
	RegCloseKey(hBaseKey);
	if(lRet != ERROR_SUCCESS)
		return S_FALSE;

	CString strDeviceClass(DeviceClass);
	if (strDeviceClass.CompareNoCase(_T("LineDisplay")))
	{
		return S_FALSE;
	}

	m_strDevName = DeviceName;
	GetInstance(m_strDevName);

#define CHECK_RESULT if(lRet != ERROR_SUCCESS) return S_FALSE;

	PortUtility::Serial_Port_Info portInfo;
	// Get port configuration from register table.
	DWORD dwSize = 256, dwType = 0;
	TCHAR szTemp[256];
	lRet = RegQueryValueEx(hServiceKey, _T("DeviceDesc"), 0, &dwType, (LPBYTE)szTemp, &dwSize);
	CHECK_RESULT;
	if (dwType != REG_SZ) return S_FALSE;
	m_strDevDescription = szTemp;

	lRet = RegQueryValueEx(hServiceKey, _T("Port"), 0, &dwType, (LPBYTE)szTemp, &dwSize);
	CHECK_RESULT;
	portInfo.strCom = szTemp;
	
	DWORD dwValue = 9600;
	lRet = RegQueryValueEx(hServiceKey, _T("BaudRate"), 0, &dwType, (LPBYTE)&dwValue, &dwSize);
	CHECK_RESULT;
	portInfo.nBoudRate = dwValue;;

	lRet = RegQueryValueEx(hServiceKey, _T("Parity"), 0, &dwType, (LPBYTE)&dwValue, &dwSize);
	CHECK_RESULT;
	portInfo.nParity = dwValue;;
	
	m_pLD->InitPort(portInfo);
	
	m_lOpenResult = OPOS_SUCCESS;
	m_bOpened = TRUE;
	*pRC = OPOS_SUCCESS;
	return S_OK;
}

STDMETHODIMP CLineDisplay::SetPropertyString(LONG PropIndex, BSTR String)
{
	return S_OK;
}

STDMETHODIMP CLineDisplay::GetPropertyString(LONG PropertyIndex, BSTR *pString)
{
	return S_OK;
}

STDMETHODIMP CLineDisplay::SetPropertyNumber(LONG PropIndex, LONG Number)
{
	if (!m_bOpened)
	{
		m_lResultCode = OPOS_E_CLOSED;
		return S_FALSE;
	}

	switch(PropIndex)
	{
	case PIDX_DeviceEnabled:
		if (!m_bClaimed)
		{
			m_lResultCode = OPOS_E_NOTCLAIMED;
			return S_FALSE;
		}

		m_bEnabled = Number;
		if (m_bEnabled)
		{
			m_pLD->Initialize();
		}
	}

	m_lResultCode = OPOS_SUCCESS;
	return S_OK;
}

STDMETHODIMP CLineDisplay::GetPropertyNumber(LONG PropIndex, LONG *pNumber)
{
	switch(PropIndex)
	{
	case PIDX_ServiceObjectVersion:
		*pNumber = g_ServiceVersion;
		break;
	default:
		break;
	}
	return S_OK;
}

STDMETHODIMP CLineDisplay::COFreezeEvents(VARIANT_BOOL Freeze, LONG* pRC)
{
	// TODO: Add your implementation code here

	return S_OK;
}

STDMETHODIMP CLineDisplay::CreateWindow(long ViewportRow, long ViewportColumn, long ViewportHeight, 
										long ViewportWidth, long WindowHeight, long WindowWidth, long *pRC)
{
	return S_OK;
}

// Release 1.6
STDMETHODIMP CLineDisplay::DefineGlyph(LONG GlyphCode, BSTR Gryph, LONG *pRC)
{
	return S_OK;
}

STDMETHODIMP CLineDisplay::ReadCharacterAtCursor(LONG *pChar, LONG *pRC)
{
	return S_OK;
}

// Release 1.7
STDMETHODIMP CLineDisplay::DisplayBitmap(BSTR FileName, LONG Width, LONG AlignmentX, LONG AlignmentY, LONG *pRC)
{
	return S_OK;
}

STDMETHODIMP CLineDisplay::SetBitmap(LONG BitmapNumber, BSTR FileName, LONG AlignmentX, LONG AlignmentY, LONG *pRC)
{
	return S_OK;
}

// Release 1.8
STDMETHODIMP CLineDisplay::ResetStatistics(BSTR StatisticsBuffer, LONG *pRC)
{
	return S_OK;
}

STDMETHODIMP CLineDisplay::RetrieveStatistics(BSTR *pStatisticsBuffer, LONG *pRC)
{
	return S_OK;
}

STDMETHODIMP CLineDisplay::UpdateStatistics(BSTR StatisticsBuffer, LONG *pRC)
{
	return S_OK;
}

// Release 1.9
STDMETHODIMP CLineDisplay::CompareFirmwareVersion(BSTR FirmwareFileName, LONG *pResult, LONG *pRC)
{
	return S_OK;
}

STDMETHODIMP CLineDisplay::UpdateFirmware(BSTR FirmwareFileName, LONG *pRC)
{
	return S_OK;
}


// Release 1.10
STDMETHODIMP CLineDisplay::ClearInputProperties(LONG* pRC)
{
	// TODO: Add your implementation code here

	return S_OK;
}

CLineDisplayImp* CLineDisplay::GetInstance(const CString &strDeviceName)
{
	if (NULL != m_pLD) return m_pLD;

	if (0 == strDeviceName.CompareNoCase(_T("VC220")))
	{
		m_pLD = new CLD_VC220();
	}
	else
	{
		// Not support now.
		/*m_pLD = new CLD_VC220();*/
	}

	return m_pLD;
}






